package com.okwanshiwu.payment.wxUtil;

import com.okwanshiwu.payment.common.CommonPayUtil;
import com.okwanshiwu.pojo.pay.CommonResult;
import com.okwanshiwu.util.MD5;
import org.apache.log4j.Logger;
import org.dom4j.*;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 微信工具类
 *
 * @author
 * @create 2017-08-01 15:32
 **/
public class WxPayUtil {

	private static Logger logger = Logger.getLogger(WxPayUtil.class);

	/**
	 * 微信签名前对参数作如下操作：
	 * 对参数按照key=value的格式，并按照参数名ASCII字典序排序
	 * @return
	 */
	public static Map<String,String> createParameters(WxProperties wxProperties){
		Map<String,String> parameters = new TreeMap<String,String>();
		parameters.put("appid", WxProperties.APPID);
		parameters.put("mch_id", WxProperties.MCH_ID);
		parameters.put("nonce_str", wxProperties.getNonce_str());
		parameters.put("body", wxProperties.getBody());
		parameters.put("attach", wxProperties.getAttach());
		parameters.put("out_trade_no", wxProperties.getOut_trade_no());
		parameters.put("total_fee", wxProperties.getTotal_fee()+"");
		parameters.put("time_start", wxProperties.getTime_start());
		parameters.put("notify_url", WxProperties.NOTIFY_URL);
		parameters.put("trade_type", wxProperties.getTrade_type());
		parameters.put("spbill_create_ip", wxProperties.getSpbill_create_ip());
		return parameters;
	}


	/**
	 * 微信支付签名算法sign
	 * 对参数按照key=value的格式，并按照参数名ASCII字典序排序
	 * 并进行签名
	 * 详情见：https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3
	 */
	@SuppressWarnings("rawtypes")
	public static String createSign(WxProperties wxProperties){
		Map<String,String> parameters = createParameters(wxProperties);
		StringBuffer sb = new StringBuffer();
		Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序（升序）
		Iterator it = es.iterator();
		while(it.hasNext()) {
			Map.Entry entry = (Map.Entry)it.next();
			String k = (String)entry.getKey();
			Object v = entry.getValue();
			if(null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=5FC964F7EB0AACC9692A26200E4A04DE");
		String sign = MD5.md5(sb.toString()).toUpperCase();
		return sign;
	}
	/**
	 * 微信支付签名算法sign
	 * 对参数按照key=value的格式，并按照参数名ASCII字典序排序
	 * 并进行签名
	 * 详情见：https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3
	 */
	@SuppressWarnings("rawtypes")
	public static String createSign(Map<String,String> parameters){
		StringBuffer sb = new StringBuffer();
		Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序（升序）
		Iterator it = es.iterator();
		while(it.hasNext()) {
			Map.Entry entry = (Map.Entry)it.next();
			String k = (String)entry.getKey();
			Object v = entry.getValue();
			if(null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=5FC964F7EB0AACC9692A26200E4A04DE");
		String sign = MD5.md5(sb.toString()).toUpperCase();
		return sign;
	}


	/**
	 * 构造xml参数
	 * @return xml格式的请求参数
	 */
	public static String wxPropertiesToXml(WxProperties wxProperties){
		//构造xml参数的时候，至少十二个必传参数
		/*
		 * <xml>
			   <appid>wx2421b1c4370ec43b</appid>
			   <attach>支付测试</attach>
			   <body>JSAPI支付测试</body>
			   <mch_id>10000100</mch_id>
			   <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
			   <notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url>
			   <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
			   <out_trade_no>1415659990</out_trade_no>
			   <spbill_create_ip>14.23.150.211</spbill_create_ip>
			   <total_fee>1</total_fee>
			   <trade_type>JSAPI</trade_type>
			   <sign>0CB01533B8C1EF103065174F50BCA001</sign>
			</xml>
		 */

		if(wxProperties!=null){
			StringBuffer bf = new StringBuffer();
			bf.append("<xml>");

			bf.append("<appid><![CDATA[");
			bf.append(WxProperties.APPID);
			bf.append("]]></appid>");

			bf.append("<mch_id><![CDATA[");
			bf.append(WxProperties.MCH_ID);
			bf.append("]]></mch_id>");

			bf.append("<nonce_str><![CDATA[");
			bf.append(wxProperties.getNonce_str());
			bf.append("]]></nonce_str>");

			bf.append("<sign><![CDATA[");
			bf.append(wxProperties.getSign());
			bf.append("]]></sign>");

			bf.append("<body><![CDATA[");
			bf.append(wxProperties.getBody());
			bf.append("]]></body>");

			if(wxProperties.getDetail() != null){
				bf.append("<detail><![CDATA[");
				bf.append(wxProperties.getDetail());
				bf.append("]]></detail>");
			}
			if(wxProperties.getAttach() != null) {
				bf.append("<attach><![CDATA[");
				bf.append(wxProperties.getAttach());
				bf.append("]]></attach>");
			}
			bf.append("<out_trade_no><![CDATA[");
			bf.append(wxProperties.getOut_trade_no());
			bf.append("]]></out_trade_no>");

			bf.append("<total_fee><![CDATA[");
			bf.append(wxProperties.getTotal_fee());
			bf.append("]]></total_fee>");

			bf.append("<spbill_create_ip><![CDATA[");
			bf.append(wxProperties.getSpbill_create_ip());
			bf.append("]]></spbill_create_ip>");

			bf.append("<time_start><![CDATA[");
			bf.append(wxProperties.getTime_start());
			bf.append("]]></time_start>");

			bf.append("<notify_url><![CDATA[");
			bf.append(WxProperties.NOTIFY_URL);
			bf.append("]]></notify_url>");

			bf.append("<trade_type><![CDATA[");
			bf.append(wxProperties.getTrade_type());
			bf.append("]]></trade_type>");

			bf.append("</xml>");
			return bf.toString();
		}

		return "";
	}

	/**
	 * 订单结果xml处理方法
	 * @param xml
	 * @return
	 */
	public static WXQueryOrderResult xmlToWXQueryOrderResult(String xml){
		WXQueryOrderResult wr = new WXQueryOrderResult();
		try {
			Document document = DocumentHelper.parseText(xml);
			Element root=document.getRootElement();
			for(Iterator it=root.attributeIterator();it.hasNext();){
				Attribute attribute = (Attribute) it.next();
				String text=attribute.getText();
				System.out.println("key是："+attribute.getName()+"，值是："+attribute.getText());
				String elementName = attribute.getName();
				String elementText = attribute.getText();
				if("return_code".equals(elementName)){
					wr.setReturn_code(elementText);
				}
				if("return_msg".equals(elementName)){
					wr.setReturn_msg(elementText);
				}
				if("appid".equals(elementName)){
					wr.setAppid(elementText);
				}
				if("mch_id".equals(elementName)){
					wr.setMch_id(elementText);
				}
				if("nonce_str".equals(elementName)){
					wr.setNonce_str(elementText);
				}
				if("sign".equals(elementName)){
					wr.setSign(elementText);
				}
				if("result_code".equals(elementName)){
					wr.setResult_code(elementText);
				}
				if("err_code".equals(elementName)){
					wr.setErr_code(elementText);
				}
				if("err_code_des".equals(elementName)){
					wr.setErr_code_des(elementText);
				}
				if("device_info".equals(elementName)){
					wr.setDevice_info(elementText);
				}
				if("openid".equals(elementName)){
					wr.setOpenid(elementText);
				}
				if("is_subscribe".equals(elementName)){
					wr.setIs_subscribe(elementText);
				}
				if("trade_type".equals(elementName)){
					wr.setTrade_type(elementText);
				}
				if("trade_state".equals(elementName)){
					wr.setTrade_state(elementText);
				}
				if("bank_type".equals(elementName)){
					wr.setBank_type(elementText);
				}
				if("total_fee".equals(elementName)){
					wr.setTotal_fee(Integer.parseInt(elementText));
				}
				if("fee_type".equals(elementName)){
					wr.setFee_type(elementText);
				}
				if("cash_fee".equals(elementName)){
					wr.setCash_fee(Integer.parseInt(elementText));
				}
				if("cash_fee_type".equals(elementName)){
					wr.setCash_fee_type(elementText);
				}
				if("coupon_fee".equals(elementName)){
					wr.setCoupon_fee(Integer.parseInt(elementText));
				}
				if("coupon_count".equals(elementName)){
					wr.setCoupon_count(Integer.parseInt(elementText));
				}
				if("transaction_id".equals(elementName)){
					wr.setTransaction_id(elementText);
				}
				if("out_trade_no".equals(elementName)){
					wr.setOut_trade_no(elementText);
				}
				if("attach".equals(elementName)){
					wr.setAttach(elementText);
				}
				if("time_end".equals(elementName)){
					wr.setTime_end(elementText);
				}
				if("trade_state_desc".equals(elementName)){
					wr.setTrade_state_desc(elementText);
				}
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return wr;
	}

	/**
	 * 查询订单结果类
	 * @param orderId
	 * @return
	 */
	public static WXQueryOrderResult orderResult(String orderId){
		QueryOrder qo = new QueryOrder(WxProperties.APPID, WxProperties.MCH_ID, "", orderId, CommonPayUtil.getRandomString(16));
		String resultXml = HttpXmlUtils.httpsRequest(WxProperties.ORDERQUERY_URL, "GET", qo.toRequestXml());
		WXQueryOrderResult wx = WxPayUtil.xmlToWXQueryOrderResult(resultXml);
		if("success".equalsIgnoreCase(wx.getResult_code()) && "success".equalsIgnoreCase(wx.getTrade_state())){
			return wx;
		}
		return null;
	}

	/**
	 * 微信清理数据
	 * @param map
	 * @return
	 */
	public static CommonResult cleanData(Map<String,String> map){
		String sign = map.get("sign");
		map.remove("sign");
		String verifySign = createSign(map);
		if(verifySign.equals(sign)){
			CommonResult cr = new CommonResult();
			cr.setAliAndWx(map.get("transaction_id"));
			cr.setOut_trade_no(map.get("out_trade_no"));
			cr.setTotal_price(Integer.parseInt(map.get("total_fee")==null?"0":map.get("total_fee")));
			cr.setPayType("wxPay");
			try {
				cr.setPayTime(new SimpleDateFormat("yyyyMMddHHmmss").parse(map.get("time_end")));
			} catch (ParseException e) {
				logger.error("回调函数的日期错误，无法转换"+map.get("time_end"));
				return null;
			}
			cr.setPrivateProp(map.get("attach"));
			return cr;
		} else {
			// TODO 验签失败则记录异常日志，并在response中返回failure.
			logger.error("验证签名失败");
		}
		return null;
	}
}
